/*
 *      misc.c
 *      
 *      Copyright 2009 Daniele Ricci <denn86@gmail.com>, Luca Saccagi <luksak86@gmail.com>
 *      
 *      This program is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation; either version 2 of the License, or
 *      (at your option) any later version.
 *      
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *      
 *      You should have received a copy of the GNU General Public License
 *      along with this program; if not, write to the Free Software
 *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 *      MA 02110-1301, USA.
 */

#ifndef _MISC_IMPL
#define _MISC_IMPL

#include "idmp.h"

#ifdef _WIN32
static void version(int argc, char **argv){
#else
void version(int argc, char **argv){
#endif
	if(argc <= 1) return;
	if(strcmp(argv[1],"-v")==0){ printf(_VERSION1); printf("\n"); exit(0); }
	if(strcmp(argv[1],"-V")==0){ printf(_VERSION); printf("\n"); exit(0); }
	return;
}


#ifdef _WIN32 
static char *strtoupr(char *str){
#else
inline char *strtoupr(char *str){
#endif
	int i,l;
	
	l=strlen(str);
	for(i=0;i<l;i++){
		if(!((str[i]<='Z')&&(str[i]>='A'))){
			str[i]=str[i]+('A'-'a');
		}
	}
	return str;
}
/**\brief Polling sulla directory degli alert dinamici
 *
 * Questa funzione efettua il polling sulla directory degli alert dinamici e li carica nel dataset
 */
#ifdef _WIN32 
static void idmp_dir_polling(AlertList *top){
#else
void idmp_dir_polling(AlertList *top){
#endif
	char *cmd;
	char *filename;
	int dirnlength=strlen(c0->dynamicArchive),filenlength,n,i,timer=0;
	struct direct **namelist;  

	int d;
	AlertList *to_delete,*old;
	executing_func *localef;
	xmlNodePtr xml_to_delete;
	
	
	while(true){
		n = scandir(c0->dynamicArchive, &namelist, 0, alphasort);
		if(n<0){
			fprintf(stderr,"ERR - Unable to scan %s\n",c0->dynamicArchive);
			vortex_exit();
			exit(-1);
		}
		for(i=0;i<n;i++){
			if((strncmp(namelist[i]->d_name,".",1) != 0)&&(strncmp(namelist[i]->d_name,"..",2) != 0)){
				filenlength=strlen(namelist[i]->d_name);
				filename=(char *)calloc(sizeof(char),dirnlength+filenlength+1);
				strncat(filename,c0->dynamicArchive,dirnlength);
				strncat(filename,namelist[i]->d_name,filenlength);
				strncat(filename,"\0",1);
				vortex_mutex_lock(&mutex);
				/*DBG*/DEBUG == DBG_MUTEX ? printf("DBG - (locked) IDMP_DIR_POLLING\n") : 0;
				top=loadIdmefFile(filename,top);
				vortex_mutex_unlock(&mutex);
				/*DBG*/DEBUG == DBG_MUTEX ? printf("DBG - (unlocked) IDMP_DIR_POLLING\n") : 0;
				cmd=(char *)calloc(sizeof(char),strlen(MOVECMD)+strlen(filename)+strlen(c0->storedir)+6);
				strncpy(cmd,MOVECMD,strlen(MOVECMD));
				#ifdef _WIN32
				strncat(cmd,"\"",1);
				#endif
				strncat(cmd,filename,strlen(filename));
				#ifdef _WIN32
				strncat(cmd,"\"",1);
				#endif
				strncat(cmd," ",1);
				#ifdef _WIN32
				strncat(cmd,"\"",1);
				#endif
				strncat(cmd,c0->storedir,strlen(c0->storedir));
				#ifdef _WIN32
				strncat(cmd,"\"",1);
				#endif
				if(system(cmd)<0){
					fprintf(stderr,"ERR - %s not executed\n",cmd);
				}else{
					/*DBG*/DEBUG == DBG_FILES ? printf("%s\n%s\n",cmd,filename) : 0;
				}
				free(filename);
				filename=NULL;
				free(cmd);
				cmd=NULL;
			}
			free(namelist[i]);
			namelist[i]=NULL;
		}
		free(namelist);
		namelist=NULL;
		timer++;
		usleep(c0->polling_time);

		vortex_mutex_lock(&mutex);
		/*DBG*/DEBUG == DBG_MUTEX ? printf("DBG - (locked) IDMP_WINDOW\n") : 0;
		idmp_window(top,&timer);
		vortex_mutex_unlock(&mutex);
		/*DBG*/DEBUG == DBG_MUTEX ? printf("DBG - (unlocked) IDMP_WINDOW\n") : 0;
		usleep(c0->polling_time);
	}	
}

#ifdef _WIN32
static void idmp_window(AlertList *top, int *timer){
#else
void idmp_window(AlertList *top, int *timer){
#endif
	AlertList *to_delete,*old;
	executing_func *localef;
	int d=0;
	to_delete=old=NULL;

	if(MSGcnt>c0->idmef_window && *timer>=(c0->idmef_window/(MSGcnt+1))*c0->reduct_rate){
		/*                                                           */
		/* Toglire ultimo (dato che si fa head_insert) alert da list */
		/* e tutti i link pendenti nelle strutture di indicizzazione */
		/*                                                          */
		MSGcnt--;
		to_delete=top;
		d=0;
		while(to_delete->next->next!=NULL){
			d++;
			to_delete=to_delete->next;
		}
		old=to_delete;
		to_delete=to_delete->next;
		old->next=NULL;
		for(localef=ef;localef;localef=localef->next){
			localef->del(to_delete);
		}		
		nxmlFreeNode(to_delete->root);
		free(to_delete);
		to_delete=NULL;
		*timer=0;
		}
	return;
}



/**\brief Inizializzazione e caricamento dello storico degli alert
 *
 * Questa funzione si occupa dell'inizializzazione delle librerie e delle strutture dati e carica nel dataset gli alert
 * presenti nella directory contenente lo storico dei messaggi IDMEF.
 */
#ifdef _WIN32 
static AlertList *idmp_init(AlertList *top){
#else
AlertList *idmp_init(AlertList *top){
#endif
	char *filename;
	struct direct **namelist; 
	int dirnlength,filenlength,i,n;	
	
	ef=NULL;
	init_executing_func();
	
	doc = xmlNewDoc(BAD_CAST XML_DEFAULT_VERSION);
	if (doc == NULL) {
			fprintf(stderr,"ERR - testXmlwriterTree: Error creating the xml document tree\n");
			exit(-1);
	}

	vortex_init();

	
	vortex_mutex_create(&mutex);
	if (!vortex_sasl_is_enabled()) {
		printf("ERR - SASL not enabled\n");
    	exit(-1);
	}
	vortex_profiles_register(PLAIN_PROFILE,NULL,NULL,NULL,NULL,frame_received,NULL);
	vortex_profiles_register(TLS_PROFILE,NULL,NULL,NULL,NULL,frame_received,NULL);

	for(i=0;i<255;i++){
		indexIp[i].sourceItem = NULL;
		indexIp[i].targetItem = NULL;
	}
	for(i=0;i<365;i++){
		CreateTime[i].top=NULL;
		AnalyzerTime[i].top=NULL;
		DetectTime[i].top=NULL;
	}
	MSGcnt=0;

	/*DBG*/DEBUG != DAEMON ? printf("Loading idmef stored archive:") : 0;
	
	dirnlength=strlen(c0->storedir);
	n = scandir(c0->storedir, &namelist, 0, alphasort);
	if(n<0){
		fprintf(stderr,"ERR - Unable to scan %s\n",c0->storedir);
		vortex_exit();
		exit(-1);
	}
	for(i=0;i<n;i++){
		if((strncmp(namelist[i]->d_name,".",1) != 0)&&(strncmp(namelist[i]->d_name,"..",2) != 0)){
			filenlength=strlen(namelist[i]->d_name);
			filename=(char *)calloc(sizeof(char),dirnlength+filenlength+1);
			snprintf(filename,dirnlength+filenlength+1,"%s%s",c0->storedir,namelist[i]->d_name);
			top=loadIdmefFile(filename,top);
			free(filename);
			filename=NULL;
		}
	}
	return top;
}

#ifdef _WIN32 
static executing_func *push_func(char pattern[3],xmlNodeList *(*func)(processingTree *this,stringList *sel,VortexConnection *cn,VortexChannel *ch),int (*parse)(processingTree *this,char *where,int index,int i),void(*delf)(AlertList *to_delete)){
#else
inline executing_func *push_func(char pattern[3],xmlNodeList *(*func)(processingTree *this,stringList *sel,VortexConnection *cn,VortexChannel *ch),int (*parse)(processingTree *this,char *where,int index,int i),void(*delf)(AlertList *to_delete)){
#endif
	executing_func *localef;
	
	if(ef==NULL){
		ef=(executing_func *)malloc(sizeof(executing_func));
		localef=ef;
	}else{
		localef=ef;
		while(localef->next!=NULL){
			localef=localef->next;
		}
		localef->next=(executing_func *)malloc(sizeof(executing_func));
		localef=localef->next;
	}
	localef->op=(char *)calloc(sizeof(char),4);
	strncpy(localef->op,pattern,3);
	localef->ex=func;
	localef->parse=parse;
	localef->del=delf;
	localef->next=NULL;
	return ef;
}
/**\brief Inizializzazione delle funzioni di parsing e filtreggio
 *
 * Questa funzione costruisce la lista delle operazioni inserendovi la stringa identificative,
 * il puntatore alla funzione di parsing e il puntatore alla funzione di filtraggio relativi alle possibili operazioni.
 */
#ifdef _WIN32 
static void init_executing_func(void){
#else
void init_executing_func(void){
#endif
	ef=push_func("IP\0",ip_filters,parse_ip,del_ip_index);
	ef=push_func("TS\0",time_filters,parse_time,del_time_index);
	ef=push_func("XX\0",xpath_filters,parse_xpath,del_xpath_index);
	//~ ef=push_func("AS\0",assessment_filters);
}

#ifdef _WIN32 
static void nxmlFreeNode(xmlNodePtr cur) {
#else
void nxmlFreeNode(xmlNodePtr cur) {
#endif
    xmlDictPtr dict = NULL;

	if (cur == NULL) return;

    if (cur->type == XML_DTD_NODE) {
		nxmlFreeDtd((xmlDtdPtr) cur);
		return;
    }
    if (cur->type == XML_NAMESPACE_DECL) {
		nxmlFreeNs((xmlNsPtr) cur);
        return;
    }
    if (cur->type == XML_ATTRIBUTE_NODE) {
		nxmlFreeProp((xmlAttrPtr) cur);
	return;
    }

    if (cur->type == XML_ENTITY_DECL) {
        xmlEntityPtr ent = (xmlEntityPtr) cur;
		xmlFree((xmlChar*)ent->SystemID);
		xmlFree((xmlChar*)ent->ExternalID);
    }
    if ((cur->children != NULL) && (cur->type != XML_ENTITY_REF_NODE))
		nxmlFreeNodeList(cur->children);
    if (((cur->type == XML_ELEMENT_NODE) || (cur->type == XML_XINCLUDE_START) || (cur->type == XML_XINCLUDE_END)) && (cur->properties != NULL))
		nxmlFreePropList(cur->properties);
    if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL) && (cur->type != XML_ENTITY_REF_NODE) && (cur->type != XML_XINCLUDE_END) && (cur->type != XML_XINCLUDE_START) && (cur->content != (xmlChar *) &(cur->properties))) {
		xmlFree(cur->content);
    }
    if ((cur->name != NULL) && (cur->type != XML_TEXT_NODE) && (cur->type != XML_COMMENT_NODE))
		xmlFree((xmlChar*)cur->name);

    if (((cur->type == XML_ELEMENT_NODE) || (cur->type == XML_XINCLUDE_START) || (cur->type == XML_XINCLUDE_END)) && (cur->nsDef != NULL))
		nxmlFreeNsList(cur->nsDef);
	
	if(cur->_private != NULL){ free(cur->_private); cur->_private=NULL; }	
	if(cur->psvi != NULL){ free(cur->psvi); cur->psvi=NULL; }
	xmlFree(cur);
}



#ifdef _WIN32 
static void nxmlFreePropList(xmlAttrPtr cur) {
#else
void nxmlFreePropList(xmlAttrPtr cur) {
#endif
    xmlAttrPtr next;
    if (cur == NULL) return;
    while (cur != NULL) {
        next = cur->next;
        nxmlFreeProp(cur);
		cur = next;
    }
}



#ifdef _WIN32 
static void nxmlFreeProp(xmlAttrPtr cur) {
#else
void nxmlFreeProp(xmlAttrPtr cur) {
#endif
    if (cur == NULL) return;

    /* Check for ID removal -> leading to invalid references ! */
	if ((cur->doc != NULL) && (cur->atype == XML_ATTRIBUTE_ID)) {
	    xmlRemoveID(cur->doc, cur);
    }
    if (cur->children != NULL) nxmlFreeNodeList(cur->children);
	xmlFree((xmlChar*)cur->name);
    xmlFree(cur);
}


#ifdef _WIN32 
static void nxmlFreeNodeList(xmlNodePtr cur) {
#else
void nxmlFreeNodeList(xmlNodePtr cur) {
#endif
    xmlNodePtr next;

    if (cur == NULL) return;
    if (cur->type == XML_NAMESPACE_DECL) {
		nxmlFreeNsList((xmlNsPtr) cur);
		return;
    }
    if ((cur->type == XML_DOCUMENT_NODE) ||
	#ifdef LIBXML_DOCB_ENABLED
	(cur->type == XML_DOCB_DOCUMENT_NODE) ||
	#endif
	(cur->type == XML_HTML_DOCUMENT_NODE)) {//
		return;
    }

    while (cur != NULL) {
        next = cur->next;
		if (cur->type != XML_DTD_NODE) {
		    if ((cur->children != NULL) && (cur->type != XML_ENTITY_REF_NODE)) 
				nxmlFreeNodeList(cur->children);
			if (((cur->type == XML_ELEMENT_NODE) || (cur->type == XML_XINCLUDE_START) || (cur->type == XML_XINCLUDE_END)) && (cur->properties != NULL))
				nxmlFreePropList(cur->properties);
			if ((cur->type != XML_ELEMENT_NODE) && (cur->type != XML_XINCLUDE_START) &&	(cur->type != XML_XINCLUDE_END) && (cur->type != XML_ENTITY_REF_NODE) && (cur->content != (xmlChar *) &(cur->properties))) {
				xmlFree(cur->content);
		    }
			if (((cur->type == XML_ELEMENT_NODE) || (cur->type == XML_XINCLUDE_START) || (cur->type == XML_XINCLUDE_END)) && (cur->nsDef != NULL))
				nxmlFreeNsList(cur->nsDef);

			if ((cur->name != NULL) && (cur->type != XML_TEXT_NODE) && (cur->type != XML_COMMENT_NODE))
				xmlFree((xmlChar*)cur->name);
			xmlFree(cur);
		}
		cur = next;
	}
}

#ifdef _WIN32 
static void nxmlFreeNs(xmlNsPtr cur) {
#else
void nxmlFreeNs(xmlNsPtr cur) {
#endif
    if (cur == NULL) return;
    if (cur->href != NULL) xmlFree((char *) cur->href);
    if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
    xmlFree(cur);
}

#ifdef _WIN32 
static void nxmlFreeNsList(xmlNsPtr cur) {
#else
void nxmlFreeNsList(xmlNsPtr cur) {
#endif
    xmlNsPtr next;
    if (cur == NULL) return;
    while (cur != NULL) {
        next = cur->next;
        nxmlFreeNs(cur);
		cur = next;
    }
}


#ifdef _WIN32 
static void nxmlFreeDtd(xmlDtdPtr cur) {
#else
void nxmlFreeDtd(xmlDtdPtr cur) {
#endif
    xmlDictPtr dict = NULL;

    if (cur == NULL) return;
	if (cur->children != NULL) {
		xmlNodePtr next, c = cur->children;

        while (c != NULL) {
		    next = c->next;
		    if ((c->type != XML_NOTATION_NODE) && (c->type != XML_ELEMENT_DECL) && (c->type != XML_ATTRIBUTE_DECL) && (c->type != XML_ENTITY_DECL)) {
				nxmlFreeNode(c);
			}
			c = next;
		}
   }
    xmlFree((xmlChar*)cur->name);
	xmlFree((xmlChar*)cur->SystemID);
	xmlFree((xmlChar*)cur->ExternalID);
    if (cur->notations != NULL)
        xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
    if (cur->elements != NULL)
        xmlFreeElementTable((xmlElementTablePtr) cur->elements);
    if (cur->attributes != NULL)
        xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
    if (cur->entities != NULL)
        xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
    if (cur->pentities != NULL)
        xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);

    xmlFree(cur);
}

#ifdef _WIN32
static void nxmlFreeDoc(xmlDocPtr cur) {
#else
void nxmlFreeDoc(xmlDocPtr cur) {
#endif
    xmlDtdPtr extSubset, intSubset;

    if (cur == NULL) return;
    if (cur->ids != NULL) xmlFree(cur->ids);
    cur->ids = NULL;
    if (cur->refs != NULL) xmlFree(cur->refs);
    cur->refs = NULL;
    extSubset = cur->extSubset;
    intSubset = cur->intSubset;
    if (intSubset == extSubset)	extSubset = NULL;
    if (extSubset != NULL) {
		cur->extSubset = NULL;
		nxmlFreeDtd(extSubset);
    }
    if (intSubset != NULL) {
		cur->intSubset = NULL;
		xmlFree(intSubset);
    }
    if (cur->children != NULL) xmlFree(cur->children);
    if (cur->oldNs != NULL) nxmlFreeNsList(cur->oldNs);

	xmlFree((xmlChar*)cur->version);
	xmlFree(cur->name);
	xmlFree((xmlChar*)cur->encoding);
	xmlFree((xmlChar*)cur->URL);
    xmlFree(cur);
}

#endif
